{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "\n",
    "<h1> <center>基于 Numpy 的面向数组有限元编程技术</center></h1>\n",
    "$$\n",
    "\\quad\n",
    "$$\n",
    "<h2><center>报告人: 魏华祎</center></h2>\n",
    "$$\n",
    "\\quad\n",
    "$$\n",
    "<h2><center>湘潭大学数学与计算科学学院</center></h2>\n",
    "$$\n",
    "\\quad\n",
    "$$\n",
    "<h3><center>weihuayi@xtu.edu.cn</center></h3>\n",
    "$$\n",
    "\\quad\n",
    "$$\n",
    "<h4><center>2017.04.08</center></h3>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 面向数组编程（Array-oriented programming)\n",
    "\n",
    "面向数组编程的核心思想是基于**多维数组及其运算**来实现相关算法。\n",
    "\n",
    "\n",
    "Users of computers and programming languages are often concerned primarily with the efficiency of execution of algorithms, and might, therefore, summarily dismiss many of\n",
    "the algorithms presented here. Such dismissal would be short-sighted, since a clear statement of an algorithm can usually be used as a basis from which one may easily derive more efficient algorithm. --- **Kenneth E. Iverson (Notation as a tool of\n",
    "    thought, 1979 ACM Turing Award Lecture)**\n",
    "\n",
    "**注:**\n",
    "\n",
    "肯尼斯·艾佛森（Kenneth E. Iverson，1920年12月17日-2004年10月19日）是一位计算机科学家，最重要的贡献是开发了APL。1979年他因对数学表达式和编程语言理论的贡献而得到图灵奖。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 面向数组编程的优缺点\n",
    "\n",
    "* **优点**:\n",
    "    - 避免写冗长的循环, 编写代码速度更高\n",
    "    - 代码简洁, 可读性更高\n",
    "    - 编程的抽象层次更接近高等数学的运算过程\n",
    "    - 可直接利用高效实现的数值代数软件包, 编写高效的代码\n",
    "* **缺点**: \n",
    "    - 需要改变已有的标量化编程思维方式\n",
    "    - 需要基于数组及其运算重构已有算法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 支持面向数组编程的语言\n",
    "\n",
    "面向数组编程的语言或软件包:\n",
    "* APL\n",
    "* J\n",
    "* Fortran 90\n",
    "* Matlab \n",
    "* Octave\n",
    "* R\n",
    "* Wolfram Language\n",
    "* Python 中的 Numpy 扩展模块\n",
    "* C++ 中基于算子重载的很多数值代数扩展包, 如 Armadillo 和 Blitz++\n",
    "* ......\n",
    "\n",
    "\n",
    "下面分别是以 C 和 Python 语言实现两个矩阵的相加的代码:\n",
    "\n",
    "\n",
    "```C\n",
    "// C 语言实现 两个矩阵相加的代码\n",
    "for (i = 0; i < n; i++)\n",
    "    for (j = 0; j < n; j++)\n",
    "        a[i][j] += b[i][j];\n",
    "```\n",
    "\n",
    "```Python\n",
    "# Python 中两个矩阵相加的代码\n",
    "A += B\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  iFEM\n",
    "\n",
    "加州大学的陈龙教授开发了 Matlab 面向数组的有限元软件包 iFEM (https://bitbucket.org/ifem/ifem/), 利用很少的代码, 可以写出高效有限元代码. 但 iFEM 的主要缺点是**面向过程**编写, 导致代码的重用性和扩展性不高, 使用起来还是比较困难的.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## FEALPy: Finite  Element Analysis Library in Python\n",
    "\n",
    "为了克服 iFEM 中存在的问题, 我们最近开发了 Python 语言的有限元软件包 FEALPy（https://github.com/weihuayi/fealpy）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "选择 Python 的原因如下:\n",
    "\n",
    "* 解释性语言，无需编译，易学易用。\n",
    "* 精心设计的语言, 允许编写结构良好且可读性强的代码(we code what we think)。\n",
    "* 支持面向对象软件开发模式，可用面向对象的方式组织有限元软件包，易重用、维护和扩展。\n",
    "* 有庞大的用户社群，包括 NASA, ANL, Google 等国际知名的科研机构和公司都把 Python 做为高性能计算的主要开发语言之一。Python 的初学者和开发者很容易从社群中获得帮助和开发文档。\n",
    "* 有丰富的科学计算基础软件包， 如：\n",
    "    + NumPy:  http://numpy.scipy.org - Numerical Python，主要提供多维数组及相关运算功能。\n",
    "    + SciPy:  http://www.scipy.org - Scientific Python，提供高效的优化、FFT,、稀疏矩阵等科学计算模块。\n",
    "    + Matplotlib: http://www.matplotlib.org - Graphics library，提供成熟 2D 和 3D 画图软件功能。\n",
    "* 对高性能计算有很好的支持，如MPI、OpenMP和CUDA等， 可直接在大型并行计算机上布署使用。\n",
    "* 很容易用其它编译语言扩展Python，如 C/C++和Fortran。\n",
    "* 开源免费。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "但 Python 也有一些问题, 如:\n",
    "\n",
    "* 开发环境不如 Matlab\n",
    "* 没有实现所有在专业软件包中找到的算法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## FEALPy 的架构设计\n",
    "\n",
    "![FEALPy 的架构设计](./figures/sa-crop.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## FEALPy 中已经实现的功能\n",
    "\n",
    "* 基础的网格数据结构、算法和可视化功能，包括二维的三角形、四边形和多边形，三维的四面体、六面体和多面体网格的数据结构；\n",
    "* 简单区域上的三角形网格生成算法，二维的界面拟合网格生成算法，曲面三角形网格生成；\n",
    "* 三角形网格的二分法加密算法。\n",
    "* 基于四叉树和八叉树的数据结构和加密粗化算法，在加密和粗化时，不再要求相邻叶子单元的层数之差最多为一层。\n",
    "* 实现了三角形和四面体网格上的任意次Lagrange有限元空间;\n",
    "* 多边形网格上的最低次虚单元空间;\n",
    "* Laplace 方程的离散、边界条件处理与求解等功能模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 面向数组的有限元编程技术\n",
    "\n",
    "有限元算法中的基本要素:\n",
    "\n",
    "* 网格\n",
    "* 有限元空间\n",
    "    + 基函数的计算\n",
    "    + 自由度的管理 \n",
    "* 离散系统\n",
    "    + 矩阵和向量的构造\n",
    "    + 求解\n",
    "* 可视化\n",
    "* ......"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 网格\n",
    "\n",
    "**目标:** 用 Numpy 中的数组来组织三角形网格中的数组结构.\n",
    "\n",
    "网格是有限元算法的基础, 最少需要两个二维数组来存储网格的信息:\n",
    "\n",
    "* 网格节点坐标数组 `point`:\n",
    "    + $N\\times 2$ 的二维数组\n",
    "    + `point[i, 0]` 和 `point[i, 1]` 分别存储第 $i$ 个网格节点的 $x$ 和 $y$ 坐标\n",
    "* 单元顶点编号数组 `cell`:\n",
    "    + $NC\\times 3$ 的二维数组\n",
    "    + `cell[i, 0]`, `cell[i, 1]` 和 `cell[i, 2]` 分别存储第 $i$ 个单元三个顶点的全局编号(即 `point` 中的行号)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "point = np.array(\n",
    "    [(0.0, 0.0),\n",
    "     (1.0, 0.0),\n",
    "     (1.0, 1.0),\n",
    "     (0.0, 1.0)], dtype=np.float)\n",
    "cell = np.array([\n",
    "        (1, 2, 0), \n",
    "        (3, 0, 2)], dtype=np.int)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "notes"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlAAAAGICAYAAACOZ96aAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzt3Xt8VPWd//H3ZwAl3EK5CAJesICEXYWCiwlbEYQlPyqK\nXbZ4WYXU6i5GBQEvRYqKRZG1XrAL+qsC6lIRpbW4BQWMt7RCxXD51YKo3IwXokFRJNzMfH9/TJKS\nkNs3mcmZybyej8c8yJz5npnP95uZyZtzvuccc84JAAAAtRcKugAAAIBEQ4ACAADwRIACAADwRIAC\nAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADw\nRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIAC\nAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADw\nRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIAC\nAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADw\nRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIAC\nAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADw\nRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIAC\nAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADw\nRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIACAADwRIAC\nAADwRIACAADwRIBKUmZ2vpmFzexfg64FAIBEQ4BKbi7oAgAASEQEqORmQRcAAEAiIkABAAB4IkA1\nMDO7q2TuUU8zW2xm+8zsczO7u+TxU8zsD2b2tZl9ZmZTKqx/gpnNNLMPzOyQmX1kZnPM7IQK7f7F\n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\nCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAA\nAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACe\nCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAA\nAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACe\nCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAA\nAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACe\nCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAA\nAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACe\nCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAA\nAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACe\nCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAA\nAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACe\nCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACeCFAAAACe/j9HFTAv/rQf7QAAAABJ\nRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f4614d2a940>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from fealpy.mesh.TriangleMesh import TriangleMesh\n",
    "import matplotlib.pyplot as plt \n",
    "%matplotlib inline\n",
    "tmesh = TriangleMesh(point, cell)\n",
    "fig, axes = plt.subplots(1, 3)\n",
    "tmesh.add_plot(axes[0], cellcolor='w')\n",
    "tmesh.find_point(axes[0], showindex=True, markersize=25, fontsize=12)\n",
    "tmesh.find_cell(axes[0], showindex=True, markersize=100, fontsize=12)\n",
    "axes[0].set_title('mesh')\n",
    "\n",
    "for ax in axes.reshape(-1)[1:]:\n",
    "    ax.axis('tight')\n",
    "    ax.axis('off')\n",
    "axes[1].table(cellText=point, rowLabels=['0:', '1:', '2:', '3:'], loc='center')\n",
    "axes[1].set_title('point', y=0.3)\n",
    "axes[2].table(cellText=cell, rowLabels=['0:', '1:'], loc='center')\n",
    "axes[2].set_title('cell', y=0.35)\n",
    "plt.tight_layout(pad=1, w_pad=1, h_pad=1.0)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "除了上述两个基本数组之外, 有限元方法中还需要更多的网格数据, 如:\n",
    "\n",
    "* 边数组 `edge`\n",
    "    + 二维 $NE\\times 2$ 数组 \n",
    "    + `edge[i, 0]` 和 `edge[i, 1]` 分别存储第 $i$ 条边的起点和终点的全局编号(即对应 `point` 数组中的行号)\n",
    "    + 如果第 $i$ 条边是边界边, 则规定从 `edge[i, 0]` 看向 `edge[i, 1]`, 网格离散区域一定在左手边\n",
    "* 边与单元的相邻关系数组 `edge2cell`\n",
    "    + 二维 $NE \\times 4 $ 的数组\n",
    "    + `edge2cell[i, 0]` 和 `edge2cell[i, 1]` 分别存储第 $i$ 条边左右两个单元的全局编号(即对应 `cell` 数组中的行号)\n",
    "    + `edge2cell[i, 2]` 和 `edge2cell[i, 3]` 分别存储第 $i$ 条边在左右两个单元中的局部编号\n",
    "    + 如果是边界边, 则\n",
    "        - `edge2cell[i, 0] = edge2cell[i, 1]` \n",
    "        - `edge2cell[i, 2] = edge2cell[i, 3]`\n",
    "        \n",
    "**注: `edge` 和 `edge2cell` 可以从 `cell` 中构造出来.**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  `edge` 和 `edge2cell` 和构造算法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\nuPXWW/noo49YsGBBoHHdeuutXHjhhfTq1Yvdu3fzyCOPsHr1apYvXx5oHHVNnDiR4uJiCgsLGThw\nIDNnzqSqqori4uLQYgpbVPMHojVeUcxnv6jwEhFphg8//JB/+Zd/YefOnXTr1o2hQ4fy4osv0qVL\nFwC2bdtW7yq1oHzyyScUFRWxbds2cnJyOPPMM1m+fDkjRowIPJYaY8aMobKykilTplBRUUFBQQHL\nli2jW7duocUUtqjmD0RrvKKYz35R4SUi0gyPPvpok+/Pnz8/oEjqe+CBB0LZ7pGUlJRQUlISdhiR\nEdX8qRGV8YpqPvtB53iJiIiIBESFl4iIiEhAVHiJiIiIBETneImIJCGVh/Nu3bo15Tb8EqVYIDpx\nBKGlnzVqYxaleKIQQ3NZWI+2EBHJBGbWKxaLvRWPx9un0k4sFiMej/sVVkqiFAtALBbbH4/HT3fO\nvR92LOngRw5FcMwiE0+m5Y8KLxGRIzCzXkDXFJs5CjjgQzh+iFIsAJWZ8qXZUj7kUNTGLErxZFT+\nqPASERERCYhOrhcREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIR\nEREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo\n8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAovERER\nkYCo8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAov\nERERkYCo8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJ\niAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIR\nEREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo\n8BIREREJiAovERERkYCo8BIREREJiAovERERkYCo8BIREREJiAqvNDOzYjOLm1mvsGORzKP8ab3M\n7LzE2H8j7FjSwczeNbN5dV5n9efNdBof/6jwSj+XmGqZWV8ze8bMdpvZTjN72My6hhSfRFu9/DGz\n/8fM5pjZOjM7YGbVIcYm6eeOvEjLmVkHM7vWzJaZ2cdm9rmZvWJm/2Zm6f5+aOyzpfXzSso0Pj5Q\n4ZV+DwMdnHPvA5hZHlAGnAT8FLgbuBhYbmZtQ4tSoqpe/gAXAT8A4sA7oUUl2eIk4N7Ev+8BJgFb\ngDnAg2EFJZLN9EWfZs45BxyoM+s2oANQ4Jz7CMDM1gJ/BoqBB4KOUaKrkfyZA/zCOfeFmf0GOC2c\nyCRLbAfOcM5trDPvfjN7ECg2szucc1tCik0kK2mPV5o1co7O5cCfaoouAOfcSmATMCaMGCW6GuaP\nc26Hc+6LsOOS5JnZiWY2z8y2m9l+M3vNzK5ssEyemf3BzPaYWYWZ/SdwNGCNtHetmb1jZlVm9qKZ\nDTWz58zs2QbLHWVm08zs7cR23zezGWZ2VM0yzrmdDYquGosTP/MbtJljZjPNbGuizQ/MbIGZdW7O\ndiU8Uc7H1kJ7vNKv9hwdMzsROAFY18hyLwMXBhiXZIZDzhGUzGFmJwAvAdV4h/Qq8f6fP2hmnZxz\n95pZe+BZ4KvALGAbcAUwgkPPD/0x8BtgNfCfwNeAPwB/Bz6os5wBfwSGAP8FvAn8E3ADcCreH4BN\n6ZH4WVmnzY7AX4DT8Q5Drge6ApckYv/Uh+1KGmVwPmYX55ymNE5AEV6S9wIK8c7N+ddGlpuRWK5d\n2DFris5UN38aee83QHXYMWpqcvweAD4Ejm8w/7+BT/H2IvwkMcaX13m/Pd5e8GrgG4l57YAdwBog\nVmfZKxK/V56tM28scBAY3GC7VyfaHNREzO2A14G3G2xnWmLdS5pYN+ntAluBeXVen1f382pSPmbr\npEONweqQ+NnYoaL9DZYRkcx3Od5f+m3MrEvNBCwHcoABeHsctjnnnqpZyTm3H/htg7bOBroA9zvn\n4nXm/zfeHoa6vgtsBDY12O4qvMNFw5uIeTbQFxjfYDuXAxucc0ubWDeV7Ur6ZWI+Zh0dagzWvsTP\noxt5r32DZUQkg5lZN+B4vL/qr2lkEYd36kFvYHMj77/V4HXvxDr1rmZ1zlWb2bsNlj0Vr3ja0cR2\nG4v5JuCHwG3OuWUN3j4ZeKKx9VLdrqRfJuZjtlLhFaxtiZ89GnmvB/Cpc+5ggPGISPrUHFFYCCw4\nzDJ/S+O2/4Z3Ds0hJ0RT5/ybGmZWDPwCmOOcuyuo7UpgMiofs5kKrwA55z42sx14u2gbGgi8GnBI\nIpI+O4DdQBvn3LOHW8jM3gO+3shbfRu8fg/vS+sUvJOZa9Zvg3dS84Y6y74DnOmcW5VMoGZ2KXA/\n8IRzbvxhFnsHOOMITTVruxKojMnHbKdzvIL3JPCtxI1UATCz8/Hux/R4aFGJiK8S5708CXzHzA75\nIrMvn1ZRCpxoZt+p894xwI8arLIO2An8yOrfVX4s8JUGyz4OfNXMGraBmbVPtF/z+hvAo8BzibYO\n50mgf6JIO5yktyvBypR8bA20xyt4d+KdaPicmc0COgE34v118FCIcUkGMO9+XlckXp6dmHdb4vV7\nzrmFoQQmh/NTYBjwkpndD7wBdMa7wnkE3u0Y7gfGA78zs7P58vL9vXUbcs4dNLPb8W4DsMrMHsfb\ns1CMd05O3Uv9f4d3X8D7zGw48ALQBu++XN8DRgGvJPJpKd5VaE8BY7wr/2v91TlXc/jpbrzfXb83\ns/lAOd7J1d8Grkksl9R2m+ivxg5DiX8inY9+f9jICvuyymyfaOR2AHjJ9j94u3134h1v7xZ2rJqi\nNzXMH7xL7uOJeQ2nZ8OMVdNhx7Ar3pfTu3hXL3+EdxXZD+os81W8m5buBirwHt/zTRq5vQJwLd5j\nfarwLuUfBKwFnm6wXBu8P+r+mli2Eu9+gbcBx9bJp8ZyqWaa0qDN4/Hu7fQ+3oVA7+Hd0+srzdlu\nYrktwIN1Xut2Eq08H1vLZIkOERGRDJS4OeUO4EnnXGNXq4kERvl4ZDrHS0QkQ5hZY7eiKcI7XKQT\nlyVQyseW0R4vEZEMYWbnATOB3+OdplAI/ADvTvNnO+f+EWJ40sooH1tGJ9eLiGSOd/HOr7oOb6/C\np3gX5dyiLzkJwbsoH5tNe7xEREREAqJzvEREREQCosJLREREJCAqvEREREQCosJLREREJCAqvERE\nREQCosJLREREJCAqvEREREQCosJLREREJCAqvEREREQC0moeGWRmvYCuYccRUZXOuffDDiLKlD9H\nlNU55NP4HwUciEAbUWwnq/MHfMkhv/raL1GKJ6Pyp1UUXmbWKxaLvRWPx9uHHUsUxWKx/WZ2eiYl\nbpCUP0eWzTnk1/jHYjHi8XhKsfjRRkTbydr8AX9yyK++9kuU4sm0/GkVhRfQNR6Pt1+4cCH5+flh\nxxIpGzduZOzYse3x/hLLiKQNgfKnCa0gh1Ie/9LSUiZPnkzYbUSxnVaQP5BiDvnV136JUjyZmD+t\npfACID8/nwEDBoQdhmQo5U/rlsr4b9y4MRJtRLGd1qSlfRW1vo5aPJlGJ9eLiIiIBESFVxYpKyvj\nkksuIS8vj1gsxtKlS8MOSTKI8qd5Zs+eTZ8+fejQoQODBg1i7dq1kWo31Xb8ygflVePSlT+pilJc\n2Zo7KryyyN69eykoKGDOnDmYWdjhSIZR/iRv0aJFTJo0iWnTprF+/Xr69+/P6NGjqaysjES7frTj\nVz4orw6VrvzJtriyNnecc1k/AQMAV15e7loLM3NLliw54nLl5eUOcMAAF4GxiuKk/GlatudQY+N/\nzjnnuAkTJtS+jsfjLi8vz82YMaPRPlq4cKFLJoeaajfZNvxsp0Zj+eBXO9meP66RHEpX/qQq2biC\niqeuw/1OysT80R4vEZFmOHjwIOXl5Zx//vm188yMkSNHsmbNGgCKi4sZPny47+0G2Y6kR7ryJ4i4\nxB8qvEREmqGyspLq6mpyc3Przc/NzWX79u0AnHjiifTu3dv3doNsR9IjXfkTRFzij1Z1OwkRkSDc\neeedYYcgGUz5k920x0tEpBm6du1KmzZtqKioqDe/oqKC7t27h95uuuITf0R1fKIaVzZS4SUi0gzt\n2rWjsLCQlStX1s5zzrFy5UqGDBkServpik/8EdXxiWpc2UiHGrPI3r172bx5c81VNGzZsoUNGzbQ\nuXNnevbsGXJ0EnXKn+RNnDiR4uJiCgsLGThwIDNnzqSqqori4mIAbrnlFj7++GMWLFjgW7vLly8P\ntB2/8kF5dah05U+64wpatuaOCq8ssm7dOoYPH46ZYWZMmjQJgKKiIubNmxdydBJ1yp/kjRkzhsrK\nSqZMmUJFRQUFBQUsW7aMbt26AbB9+3Y++OAD39sNsh2/8kF5dah05U+64wpatuaOCq8sct5550Xm\nafGSeZQ/zVNSUkJJSUmj782fPz8t7QbZjl/5oLxqXLryJ1V+5Z8fsjV3dI6XiIiISEBUeImIiIgE\nRIWXiIiISEBa1TlepaWlbNy4MewwImXr1q1hh5AxlD+Nay05lMr4v/DCC5FoI4rttJb8gZb3lV99\n7ZcoxZOJ+WM1l2lmMzMbFIvF1mTjSXp+iMVixOPxwc65F8OOJYqUP0eWzTnk1/gn+ij0NiLcTlbm\nD/iTQ371tV+iFE+m5U9r2eN1IB6Ps3DhQvLz88OOJVI2btzI2LFjAQ6EHUuEKX+a0ApyKOXxLy0t\nZfLkyaG3EcV2WkH+QIo55Fdf+yVK8WRi/rSWwguA/Px8BgwYEHYYkqGUP61bKuNfczgm7Dai2E5r\n0me5WDcAABa0SURBVNK+ilpfRy2eTKOT67PM7Nmz6dOnDx06dGDQoEGsXbs27JAkQ8ydO5f+/fuT\nk5NDTk4OQ4YM4Zlnngk7rEgqKyvjkksuIS8vj1gsxtKlS31rO9X/w37H5sfvFP1eqi+d+dNSd911\nFwMHDuS4444jNzeXyy67jE2bNoUdVlbmjgqvLLJo0SImTZrEtGnTWL9+Pf3792f06NFUVlaGHZpk\ngJ49ezJjxgxeeeUVysvLGTFiBJdeemnoJ89G0d69eykoKGDOnDmYmW/t+vF/2M/Y/IhHv5cOla78\nSUVZWRnXXXcdL730EitWrODgwYOMGjWKffv2hRZT1uaOcy7rJ2AA4MrLy102O+ecc9yECRNqX8fj\ncZeXl+dmzJhx2HXKy8sd4IABLgJjFcWpteRPYzp37uzmzZvX5DLZnkNHGn8zc0uWLGmyjxYuXOiS\nyaGm/g8n28aRYmtOO37Ec6TfS9meP+4IOeRn/vhpx44dzsxcWVlZaPEk852WifmjPV5Z4uDBg5SX\nl3P++efXzjMzRo4cyZo1a0KMTDJRPB7nscceo6qqisGDB4cdTsa5/fbb6dOnT7PWidr/YT/iidpn\nyhQtyR+/7dq1CzOjc+fOoWw/m3NHhVeWqKyspLq6mtzc3Hrzc3Nz2b59e0hRSaZ57bXX6NSpE0cf\nfTQlJSUsXryYvn37hh1WxunWrRunnHJKs9aJ2v9hP+KJ2mfKFC3JHz8557j++usZOnQo/fr1CyWG\nbM4dFV4iUqtv375s2LCBl19+mR//+MeMGzeON998M+ywMs61117Ln//857DDkAwVdv6UlJTwxhtv\n8Nhjj4UWQzZrVbeTyGZdu3alTZs2VFRU1JtfUVFB9+7dQ4pKMk3btm056aSTADjrrLN4+eWXmTVr\nFvfdd1/IkWW/qP0f9iOeqH0mObLx48dTWlpKWVkZPXr0CC2ObM4d7fHKEu3ataOwsJCVK1fWznPO\nsXLlSoYMGRJiZJLJ4vE4X3zxRdhhtApR+z/sRzxR+0zStPHjx7NkyRJWrVpFr169Qo0lm3NHe7yy\nyMSJEykuLqawsJCBAwcyc+ZMqqqqKC4uDjs0yQC33norF154Ib169WL37t088sgjrF69muXLl4cd\nWuTs3buXzZs311yxxpYtW9iwYQOdO3emZ8+ezJ49m8WLF7NixYpmtdvU/+Fkx+FIsQUdj34vHSpd\n+ZOKkpISHn30UZYuXUrHjh1r9zTl5OTQvn37wOKoK1tzR4VXFhkzZgyVlZVMmTKFiooKCgoKWLZs\nGd26dQs7NMkAn3zyCUVFRWzbto2cnBzOPPNMli9fzogRI8IOLXLWrVvH8OHDMTPMjEmTJgFQVFTE\nvHnzqKysZMuWLc1u14//w0eKLeh49HvpUOnKn1TMnTsXM2PYsGH15s+fP59x48YFGkuNbM0dFV5Z\npqSkhJKSkrDDkAz0wAMPhB1CxjjvvPOafEDw1KlTmTp1aovaTvX/8JFiCzoev9rIJunMn5aKygOv\nG8rG3NE5XiIiIiIBUeElIiIiEhAVXiIiIiIBaVXneJWWluqBvw1s3bo17BAyhvKnca0lh1IZ/xde\neCESbUSxndaSP9DyvvKrr/0SpXgyMX+s5nLWbGZmg2Kx2JqonjwYtlgsRjweH+ycezHsWKJI+XNk\n2ZxDfo1/oo9CbyPC7WRl/oA/OeRXX/slSvFkWv60lj1eB+LxOAsXLiQ/Pz/sWCJl48aNjB07FuBA\n2LFEmPKnCa0gh1Ie/9LSUiZPnhx6G1FspxXkD6SYQ371tV+iFE8m5k9rKbwAyM/PZ8CAAWGHIRlK\n+dO6pTL+NYdjwm4jiu20Ji3tq6j1ddTiyTQ6uV5EREQkICq8ssS0adOIxWL1pn79+oUdlmQQ5VBy\n7rrrLgYOHMhxxx1Hbm4ul112GZs2bUq53bKyMi655BLy8vKIxWIsXbo01Hb8+pzp6q9MFdX+mDt3\n7v/f3v2HVHn/fRx/XSe7KaQOuMqcaNRgaURagkuRlRZlREX/BBui9tfgzIYkG5tQWyxq/hXBShmi\nBUU1glDYoUQXegb98tRkUtRcwV3NLAdFaTnpnPuPffM7d686di6vX+f5ACGv4t37fK6X9fbyc51L\nOTk58vv98vv9Kiws1OnTp+1uSwcOHND8+fM1ffp0LV++XJcuXbK7pbgxeHnI4sWLNTAwoHv37une\nvXv66aef7G4JLkOGXi8UCmnbtm26cOGC2tvbNTo6qjVr1ujp06dx1R0aGlJubq4OHjwowzBsr2PW\n65ys9XIrp65HRkaG6urqdPnyZYXDYZWUlGjTpk223rV44sQJ1dTUaNeuXbpy5YpycnK0du1aDQ4O\n2taTGRJqj5fXJSUluf4ZVrAXGXq9YDA47vNDhw5pzpw5CofDKioqeuO6paWlKi0tlSTFc7e5WXXM\nep2TtV5u5dT1WL9+/bjPd+/erfr6ep0/f962DfT79u3TRx99NPasyIaGBv3www9qamrSZ599ZktP\nZuCKl4f8+uuvSk9P1zvvvKOysjLdvn3b7pbgMmRo4h4+fCjDMJSSkjJ2bOvWrSouLraxK/P92+u0\ns45XODE/kUhEx48f1/DwsAoKCmzpYXR0VOFwWKtWrRo7ZhiGVq9erXPnztnSk1m44uURy5cv16FD\nh7Rw4UL19/frq6++0vvvv6/e3l4lJyfb3R5cgAxNXDQaVXV1tYqKisbth0tLS4vrapPTvOx12lXH\nK5yWn97eXhUUFOjZs2eaMWOGTp06paysLMv7kKTBwUE9f/5cqamp446npqbq+vXrtvRkFgYvj1i7\ndu3YrxcvXqz8/HzNmzdP33//vbZu3WpjZ3ALMjRxgUBAV69eHXsn7xf27NljU0eT42Wv0646XuG0\n/GRlZamnp0ePHj3SyZMnVV5erq6uLtuGL69i8PIov9+vd999V319fXa3ApciQ69WVVWlYDCoUCik\ntLQ0u9uZNGa9zkRZr1g5cT2SkpK0YMECSdLSpUt18eJF7d+/X/X19Zb3MmvWLE2ZMkUDAwPjjg8M\nDGju3LmW92Mm9nh51JMnT/Tbb7855gsa7kOGXq6qqkotLS06e/asMjMz7W5n0pj1OhNlvWLllvWI\nRCIaGRmx5e+eOnWq8vLy1NHRMXYsGo2qo6NDhYWFtvRkFq54ecSnn36qDRs2aN68ebp7966+/PJL\nJSUl6YMPPrC7NbgEGYpNIBDQsWPH1NraquTk5LHvyP1+v6ZNmyZJqq2t1d27d3X48OGY6w4NDamv\nr29sb8/NmzfV09OjlJQUZWRkWF4nltdpZR2vmKz8xKu2tlbr1q1TZmamHj9+rKNHj6qzs1NtbW2W\n9fBP27dvV2VlpfLy8pSfn699+/ZpeHhYlZWVtvVkBgYvj7hz544+/PBD/fHHH5o9e7aKiop0/vx5\nvfXWW3a3BpcgQ7FpaGiQYRhauXLluOPNzc1jt7339/dP+I7Q7u5uFRcXyzAMGYahmpoaSVJFRYWa\nmposrxPL67SyjldMVn7idf/+fVVUVKi/v19+v19LlixRW1ubSkpKLO3j77Zs2aLBwUHt3LlTAwMD\n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\nvAAAACzyf4bG0CbXbhOIAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f461504d390>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from fealpy.mesh.mesh_tools import unique_row\n",
    "\n",
    "point =np.array(\n",
    "    [(0.0, 0.0),\n",
    "     (1.0, 0.0),\n",
    "     (1.0, 1.0),\n",
    "     (0.0, 1.0)], dtype=np.float)\n",
    "\n",
    "cell = np.array([\n",
    "        (1, 2, 0), \n",
    "        (3, 0, 2)], dtype=np.int)\n",
    "localEdge = np.array(\n",
    "    [(1, 2),\n",
    "     (2, 0),\n",
    "     (0, 1)], dtype=np.int)\n",
    "\n",
    "totalEdge = cell[:, localEdge]\n",
    "totalEdge = totalEdge.reshape(-1, 2)\n",
    "stotalEdge = np.sort(totalEdge, axis=1)\n",
    "uedge, i0, j = unique_row(stotalEdge)\n",
    "NE = i0.shape[0]\n",
    "\n",
    "i1 = np.zeros(NE, dtype=np.int) \n",
    "NC = cell.shape[0]\n",
    "i1[j] = np.arange(3*NC)\n",
    "\n",
    "edge2cell = np.zeros((NE, 4), dtype=np.int)\n",
    "t0 = i0//3\n",
    "t1 = i1//3\n",
    "k0 = i0%3\n",
    "k1 = i1%3\n",
    "edge2cell[:, 0] = t0\n",
    "edge2cell[:, 1] = t1\n",
    "edge2cell[:, 2] = k0\n",
    "edge2cell[:, 3] = k1\n",
    "\n",
    "edge = totalEdge[i0]\n",
    "\n",
    "from fealpy.mesh.TriangleMesh import TriangleMesh\n",
    "import matplotlib.pyplot as plt \n",
    "%matplotlib inline\n",
    "tmesh = TriangleMesh(point, cell)\n",
    "fig, axes = plt.subplots(2, 4)\n",
    "tmesh.add_plot(axes[0, 0], cellcolor='w')\n",
    "tmesh.find_point(axes[0, 0], showindex=True, markersize=25, fontsize=12)\n",
    "tmesh.find_cell(axes[0, 0], showindex=True, markersize=100, fontsize=12)\n",
    "axes[0, 0].set_title('mesh')\n",
    "\n",
    "for ax in axes.reshape(-1)[1:]:\n",
    "    ax.axis('tight')\n",
    "    ax.axis('off')\n",
    "axes[0, 1].table(cellText=cell, rowLabels=['0:', '1:'], loc='center')\n",
    "axes[0, 1].set_title('cell', y=0.6)\n",
    "axes[0, 2].table(cellText=totalEdge, rowLabels=['0:', '1:', '2:', '3:', '4:', '5:'], loc='center')\n",
    "axes[0, 2].set_title('totalEdge', y=0.85)\n",
    "axes[0, 3].table(cellText=np.sort(totalEdge, axis=1), rowLabels=['0:', '1:', '2:', '3:', '4:', '5:'], loc='center')\n",
    "axes[0, 3].set_title('Sorted totalEdge', y=0.85)\n",
    "axes[1, 0].table(cellText=i0.reshape(-1,1),  loc='center')\n",
    "axes[1, 0].set_title('i0', y=0.85)\n",
    "axes[1, 1].table(cellText=i1.reshape(-1,1),  loc='center')\n",
    "axes[1, 1].set_title('i1', y=0.85)\n",
    "axes[1, 2].table(cellText=edge2cell,  rowLabels=['0:', '1:', '2:', '3:', '4:'], loc='center')\n",
    "axes[1, 2].set_title('edge2cell', y=0.85)\n",
    "axes[1, 3].table(cellText=edge,  rowLabels=['0:', '1:', '2:', '3:', '4:'], loc='center')\n",
    "axes[1, 3].set_title('edge', y=0.85)\n",
    "plt.tight_layout(pad=1, w_pad=1, h_pad=1.0)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "下面给出网格的数据结构示意图："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlEAAAGICAYAAABhpbWkAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzs3Xl8VdW5//HPcxIkQQZlkEkZLChYFQpWQHBAuFLrgEMv\n2tYCdbhVQBBw+DmA2jqU9uLUC7VXQfHSWhRr0ZqCiqhBUSBF2irgADgnEgSZAmLO8/tjn8QkZDwZ\n9jk53/frtV9w9ll772fts3byZO211zF3R0RERERqJhJ2ACIiIiLJSEmUiIiISByURImIiIjEQUmU\niIiISByURImIiIjEQUmUiIiISByURImIiIjEQUmUiIiISByURImIiIjEQUmUiKQsM3vZzJaFHYdI\nMjCzqJlNL/F6bGxdlzDjCpOSKBFJZQ5E49nQzH5sZpPqOB6RZOKxJWWlhx2AiEiI/qMW2/4E+C5w\nfx3FIiJJRkmUiKQsd/8m7BhEJHnpdp6IJA0zuy02BuNoM3vCzL4ys3wzu8/MmpYol2Zm08zsfTPb\na2abzOxOMzuozP5eNrOXSrw+Nbb//zSzm83sYzMrMLMXzew7JcotA84CusbKR81sY0OcA5GaMrNO\nZjbHzD6NXQ8bzWy2maXH3m8Vu4Y+ir3/npldb2YWduyJTj1RIpJMisZfPAFsAv4fMBCYCBwCjI29\nPwcYHSv338AA4EagF3BhOfsr6/8BhcBvgVbADcB8YFDs/Tti6zsD1wAG7KpNxUTqg5l1BFYBLYE/\nABsI2u2PgGZmth94FegIPAh8DJwE3A10AKaEEHbSUBIlIsnoA3e/IPb/35vZTuAqM/tvgh720cD/\nuvuVsTIPmtkWYKqZnerur1Sx/6ZAH3cvBDCz7cB9ZnaMu7/j7kvN7FPgEHd/vM5rJ1J3fg0cBpzo\n7mtKrL8NwMxuAboDfd29qDf1ITP7HLjWzGa6+6cNGXAy0e08OUCJWxoXVF1apME5MKvMut8R9Ab9\nMLY4cG+ZMjNjZc6qxjHmFiVQMdmxbY+MJ2CRMMRux40EnimTQJX0I4L2/ZWZtSlagKUEHS2nNEy0\nyUk9UVKRlH5sVRLe+2Vef0AwVUE3gmQnWraMu+fFepS6VmP/H5d5vS3276E1jlQkPO0IbuO9XUmZ\nnsBxwJZy3nOCXiypgJIoqYgGFEoyKS/pr80fAoUVrNd1IY1NBHgBmEH57fvdhg0nuSiJEpFk1BP4\nsMTrHgS/DDbH/o3EymwoKmBmhxEMPi+5XW2ot1YS3RZgB3BsJWU+AJq7u2buj4PGRCWQEo9v9zSz\n+Wa23cy+MLNfxt4/wsz+Gnus+3Mzm1Jm+4PM7PbY46l7Y4+rzijnse7/MLNsM9tmZjvNbL2Z3Vkm\nHAcilT3mLRISA8aXWTeRoM3+HciKlbmmTJmpsTLP1VEcuwme0BNJSO7uwF+Bc8ysXwXFngAGmdkZ\nZd+ITX2QVp8xJjv1RCWWor9sFwDvEDxWfRZws5l9CfyCYLDf9cBPgd+a2Up3Xx4bQPgswaOpfwDW\nE9znnkzwF/kFAGZ2TKzcW8A0YB/BX/EnlYnFCB4Jr+wxb5GwdDezRcBigrb7U2C+u/8LwMzmAf9l\nZocCrxBMcTAa+Es1nsyrrhxglJnNJHiEfJe7/62O9i1SV24imJn/VTP7X2Ad0IlgQPlggp/v5wJ/\nM7NHCdr1wcDxBL83ugFfNnjUSUJJVGJ6w93HAZjZQwS3KP4b+H/u/t+x9X8GPgMuBZYT/BI5HTjF\n3VcU7cjM3iZ4BHygu79BcDE1Ac50921UrtLHvOustiI148BFwK8I5rL5BniA4I+LIpcR3KYYC5wH\n5AJ3Ar+sYH+Vva5o/WygT+wY1xDcJlQSJQnF3T8zswEE18tPCAaaf0rQY7vH3b8xs1MIkq3/BH5G\ncAvwXWA68FXJ3aHb2KUoiUo8TjBRYPDCPWpmqwkeU51bYv1XZraBbx+5/hHBXxjvxh5PLbKMoFdp\nKPAGsD22/nwzeyTW3VuRyh7zVhIlYdri7qMqetPdowQTYt5R2U7cfWiZ168AB9y+cPcPy6539z0E\nv3BEEpq7fwL8vJL39wC3xJbK9lP2GpgHzKuLGJOVxkQlpo/KvP4K2OvuZbtUv+LbR657EnwZ6pYy\nywZKP6a6AHgNeAjIM7PHY19xUd5TGXrMW0REpALqiUpM5T1eXdUj1xHgXwRjoCpMiNx9L3CKmQ0l\nGG/1A4JbI0vN7IwyPVN6zFtERKQCSqIajw+A46v7mGqs3DKCaf1vJLjtMRR4qdINRUREBNDtvMbk\nCeBwM7ui7BtmlmFmzWL/L+9W3FqC3qWm9RuiSO24++3unlbOrW0RkQannqjG4/+AUQRP4g0lGPeU\nBvQmeOLiDOAfwPTYkxjPETxN1B64imAc1vIQ4hYREUlKSqKSR6WPXbu7m9lIgjFRowke694DbCT4\nItaiqfsXEXx32M+BtkA+8DJwm7vvrO7xREREUp1V/oS7iIiIiJRHY6JERERE4qAkSkRERCQOSqJE\nRERE4qAkSkRERCQOSqJERERE4qAkSkRERCQOSqJERERE4qAkSkRERCQOSqJERERE4qAkSkRERCQO\nSqJERERE4qAkKg5mdoyZPWFmH5jZbjPbYmavmNnZYcdWXWZ2s5lFzeyfYcdSETM7wcz+x8z+bWa7\nzOxDM1tgZj3Djk1ERCQ97ACSVFegOfAo8BnQDLgQeMbM/svdHw4xtiqZWWfgRmBX2LFU4QbgJOBJ\n4J9AB+Bq4B9mNsDd3wkzOBERSW3m7mHH0CiYmQH/AJq6+zFhx1MZM/sz0IYgiW7j7seHHFK5zGwg\nsNrdvymxrgfwL+BJdx8dWnAiIpLydDuvjniQjX4MHBJ2LJUxs1OAC4Brwo6lKu7+RskEKrbufeBt\noHc4UYmIiAR0O68WzKwZkAm0AkYCZwKPhxpUJcwsAjwAPOTubwedZ0mpPfDvsIMQEZHUpiSqdmYC\nv4j9Pwo8RTBmJ1FdBXQBTg87kHiZ2SVAZ+CWsGMREZHUpiSqdu4lGPTcCRgFpAFNQ42oDDPLBFoS\nxHY78Et3/zLcqOJjZr2A/wFeAx4LORwREUlxGhNVC+7+rru/5O7z3f1coAXwTNhxAZjZEIvYUwRP\n4OUCnxAkeP8INbA4mVl74DlgG/CfriciREQkZOqJqqbY3ESXAt2AzcBcd3+vTLGFwINm1rOc9xqM\nmV0FzKI1hZxAhCbAcxiZNGMPL5vZLcCfgAygiZl1BXa4+7awYo7FXe45NrOWwGKCHrUh7p4bWpAi\nIiIxmuKgGszs5wYPt4RoX4i8BdEdEHG4zN0fLVFuIsEtvgHuvjqkWIcArzIAYwRBX+NmYF6swLcf\nd8kP3oH73X1KA4V5gErO8S+A0cD3gGHuvjKsGEVEREpSElUFM+tpsP5yiNxP8CjeR8CvgDkQdTja\n3d83s3TgTeBo4DB33xNKvBF7itacy3jSi2/W7okFDUG6lEUhO3mToGenOTAR2Ojubzd8xOWf4wKC\nEfpzgiJfA+e6+5Iw4hMRESmPbudV7dKWEH0AIhmxFdcA24GDwPbBMjP7AjiSYKqDlcD/hDR9QBpw\nPidgpUa7NQN6lXi9nTSWMAjIIxgndT5AiFMe9G8B9gDB/UUIEqmMb9//EGhrZj8tuZG7/7GhAhQR\nESlLSVTVuvUtkUABXEzQQ+JgwOHp6emHN2vWzNu3bx899NBD+wP9wwh0//79rFmzxmhdRcFDAbDm\nzZu3LywstOOOO+5n9R9dxd5///2047780jLKrC/RLdaD8p/GUxIlIiKhURJVtc1vQbQAIpmxFaOA\nc4DOaWlMue467r77bggSqrSwggQoKCigeYvmRL+MVl5wG0TSInzxxReWmZkJIbeDG2+8kf/97W8p\nKCwks8T6LKADFO6A37r7jWHFJyIiUh5NcVC1uTsgMpFgnA6xfycCO9y57LLLwousjMzMTEaOHEn6\nW+nB1J/liUL6W+mcf975xBKo0J177rlsKyzkag48xzuD5HROaMGJiIhUQElUFdz9PYfL5kC0AzDU\njM5paTwSifDwnDn06NEj7BBLmTJ5CoVfFMISDkykosBiKPyikMmTJ4cQ3YHy8vIYM2YMkbQ0Ho2d\n21MJeqBiA/cvi31fnoiISEJRElUN7v6ow9E7zfZv79OHX1x3Hes3bGDs2LFhh3aAIUOGMHv2bGyl\nkf6HdFgBrAdWQPof0rFVxuzZsxk8eHDYoZKXl8fJJ5/M5s2bee6551j/7ruc89Of8iqwAx6NPfn4\naNhxioiIlEdTHNRAenr6rt/85jcHT5kS2nRK1fbaa69x77338vRfnyZaGCWSFuH8885n8uTJCZdA\nPfvss4wYMQKAlStXMmDAAIDj3f1foQYpIiJSCQ0sb6QGDx7M4MGDKSgoYMeOHbRs2TJhxkBVlECJ\niIgkEyVRjVxmZmbCJE+gBEpERBoPjYmSBqMESkREGhMlUdIglECJiEhjoyRK6p0SKBERaYw0Jkrq\nlRKo+mVmXYC2tdjFQQRf8JyKUrnu+e7+UdXFRKQySqKk3iiBql9m1iUSiWyIRqNlv3aw2iKRCNFo\nFV8T1EileN33mtnRSqREakdJlNQLJVANom00Gs2YP38+vXv3rvHGWVlZTJs2jXi3T2apXPd169Zx\nySWXZBD0YCqJEqkFJVFS55RANazevXvTr1+/Gm+3bt26Wm2fzFK57iJSdzSwXOqUEqjwzZo1i+7d\nu5OZmcnAgQNZtWpV2CHVWE3r8OSTT9K7d28yMzPp06cPf//73xso0rqXynUXSTZKoqTOKIEK34IF\nC5g6dSq33347a9asoU+fPowYMYL8/PywQ6u2mtbh9ddf5yc/+QlXXHEFb731FiNHjuS8887jnXfe\naeDIay+V6y6SlNxdSzWXtLS0XTNnzvQw7dq1y6dPn+4/+MEPvHXr1m5mPm/evFBjcnfPzc31nj17\nepMmTXzx4sVx7+fNN990wIHjPAE+80RegH6A5+TkFJ+/AQMG+MSJE4tfR6NR79y5s8+YMeOAcz1/\n/nwvu30iqEkd3N0vuugiP+ecc0qtGzhwoF911VUVHiOV656Tk1N0jfXzBGjHWrQk86KeqCSTn5/P\nr371K9avX0/fvn0xs7BDUg9Ugti/fz85OTkMGzaseJ2ZMXz4cFasWAHA2LFjGTp0aFghVqk6dShr\nxYoVDB8+vNS6ESNGVFg+UaVy3UWSlQaWJ5lOnTqRm5vLYYcdRk5ODt///vdDjUcJVOLIz8+nsLCQ\n9u3bl1rfvn17NmzYAATtJ5FVpw5l5ebmlls+Nze33uKsD6lcd5FkpSQqyTRp0oTDDjss7DAAJVDJ\n6K677go7BBGRRkO38yQuSqAST9u2bUlLSyMvL6/U+ry8PDp06BBSVDUTTx06dOiQ1HUuksp1F0lW\nSqISnLuTn5/P5s2byc/Px93DDkkJVIJq0qQJ/fv3Z+nSpcXr3J2lS5dy0kknhRhZ9cVTh0GDBpUq\nD/DCCy8waNCgeo21rqVy3UWSlZKoBLV9+3buv/9+evXqSbt27ejevTvt2rWjV6+e3H///Wzfvj2U\nuJRAJbYpU6bw0EMP8dhjj7F+/XquvPJK9uzZw9ixYwG48cYbGTNmTLhBVqGqOowePZqbbrqpuPyk\nSZNYvHgx99xzDxs2bOC2224jJyeHCRMmhFSD+KVy3UWSkcZEJaAlS5YwatSF7Nmzh5NPhh//GFq0\ngJ074dVXN3LttZOZPv1m7rzz1w0alxKoxDdq1Cjy8/OZPn06eXl59O3blyVLltCuXTsgGIj88ccf\nhxxl5aqqwyeffEJ6+rc/ugYNGsSf/vQnbr75Zm6++WZ69uzJokWLOOaYY8KqQtxSue4iSSnsORaS\naWmIeaIWL17s6elpPnBgxJ96Cl+27MDlqafwgQMjnpYWabB5oupqHqiqaJ6o6i+UM09UTSTqXEkN\nIZXrrnmitGipu0W38xLI9u3bGTXqQk44wbnjjiitW5dfrnVruOOOKL17Bx/inj176jUu9UCJiIgc\nSElUApk3bx579uzhuuuipKVVXjYtDX72s2CQ+fLly+stJiVQIiIi5dOYqATh7sye/TtOPpkKe6CK\nPP007N4NW7YErxct+it33HEHZsbEiRNp0aJFncSkBCo5ZGVlsW7duhpv99prr9Vq+2SWynXftGlT\n2CE0CDPrArStxS4OAr6uo3Dqk+KsW/nu/lF1C5t7+I/MJ4v09PRdv/nNbw6eMmVKne87Pz+fdu3a\nceutcNpplZf98Y/hiy+C/7sHSyQSdCpu2rSJLl261DqesBKolStXMmDAAIDj3f1fDXLQJGVmAyOR\nyIpoNBr3PiKRCLXZPpmp7tFB7v5G2LHUBzPrEolENkSj0Yx495Es7UNx1q1IJLI3Go0eXd1ESj1R\nCWLXrl1A8BReVR5//Nv/r14N110HH3zwAd26dauTWNQDlTS+jkajzJ8/n969e9d446ysLKZNmxb3\n9sksleu+bt06LrnkEkiOXoF4tY1GoxmN/dpQnHUrdm1kEPRgVq83KuyR7cm01OfTeVu2bHHAb721\n/CfyKlqmT8cBz8/Pr5M4GuopvIro6bzqL5R5Ou/VV1/1c845xzt16uRm5osWLar0XCfiE2o1rYO7\n+7Jly7xfv37etGlT79mzpz/66KNVbpOIdS/yP//zP96tWzfPyMjwAQMG+MqVKyst/8QTT3ivXr08\nIyPDjz/+eM/Kyqq0fCo8nVf22qjpeQ2zfdTkGggzzrvuusu///3ve4sWLfywww7z8847zzds2FBu\n2bCvt+p+9vFcGxpYHofVq1czYcIEjj32WJo3b07Xrl256KKLeO+99+LeZ5s2bTjqqO/w6qtWo+2y\ns42jjvoOrasYSLV7925uvfVWzjzzTNq0aUMkEuGxxx4rVSbReqDM7Bgze8LMPjCz3Wa2xcxeMbOz\nQw0sQe3evZu+ffsye/ZszGrWjhJFTeuwefNmzj77bIYNG8batWuZNGkSl19+OS+88EIDRFv3FixY\nwNSpU7n99ttZs2YNffr0YcSIEeTn55db/vXXX+cnP/kJV1xxBW+99RYjR47kvPPO45133mngyBNb\nTc9rmJLlOs7Ozubqq6/mzTff5MUXX2T//v2cccYZFBQUhB1aKfX+2Vc329LybU/Uj370I+/UqZNP\nmjTJ58yZ43feead36NDBmzdv7m+//XbF6XAV7rvvPk9Ptwrnhyq7LFyIp6eb33///VXue/PmzW5m\n3q1bNz/99NM9EomUml8q7B6oIiV7ooAzgSxgGnAZcDXwMhAFLvcEaBNhLlQyT1Sy9kSVVJ06XH/9\n9X7ccceVWnfxxRf7mWeeWel2iVr3AQMG+MSJE4tfR6NR79y5s8+YMaPc8hdddJGfc845pdYNHDjQ\nr7rqqgqPkYo9UTU9r4nSPhK5J6qsLVu2uJl5dnb2Ae+FGWdNPnv1RDWQqVOn8uGHH3Lfffdx6aWX\nctNNN5Gdnc0333zDr38d/yziY8aMoVmzZvz2txEKCysvW1gIM2dGaNasGaNHj65y3506dSI3N5dN\nmzbxm9/8pugHDZB4PVBF3P3v7v5Dd/+Vu89x998BQ4G1QN2P7m/kbrvtNrp37x52GHXqjTfeYPjw\n4aXWjRgxghUrVoQUUfz2799PTk4Ow4YNK15nZgwfPrzC+qxYsaLR1L++VOe8jh07lqFDh4YVYqOw\nfft2zKzKuyINKZ5rqqaURMVh4MCBpb56AaBHjx5897vfrdXj0occcghPPPEUq1cbt9wSYevW8stt\n3Qq33BJh1SrjySf/wiGHHFLlvps0acJhhx12wPpETaAq4kH29zFQdaWllHbt2tGjR4+ww6hTubm5\ntG/fvtS69u3bs2PHDvbt2xdSVPHJz8+nsLCw3Prk5uaWu01F9a+ofCqqznnt1KkTXbt2DSO8RsHd\nueaaaxgyZEhCfeVQPNdUTenpvDqUl5fHscceW6t9jBgxgr/97TlGjbqQiy8Ovjvv5JO9+LvzsrON\n7Gxo1iyT5577C2eccUbcx/rqq6+SIoEys2ZAJtAKGElwm+/xSjeSA4wfP57x48eHHYZIwrnrrrvC\nDiGpjRs3jnfeead4/rVUoiSqjsyfP59PP/2UO+64o9b7GjFiBB9++AmPPfYYs2Y9wC9/+UHxe0cd\ndSQzZ05kzJgxtGrVqlbHufPOO/nyyy8TOoGKmQn8Ivb/KPAUwfgoSXEdOnQgLy+v1Lq8vDxatmxJ\n06ZNQ4oqPm3btiUtLa3c+nTo0KHcbSqqf0XlU1E851Wqb8KECWRlZZGdnU3Hjh3DDqeUhvjsdTuv\nDqxfv54JEyYwePDgao1Pqo5DDjmEiRMnsn79e+Tn57Np0yby8/NZv/49Jk6cWKsEauvWrbg7+fn5\nyZBAAdwLDAdGEww0TwOS6zek1ItBgwaxdOnSUuuef/55Bg0aFFJE8WvSpAn9+/cvVR93Z+nSpZx0\n0knlblNe/V944YWkrH99iee8SvVMmDCBRYsWsWzZsjqZ5LmuNcRnr56oGnB3du7cSUFBAZmZmUCQ\n0Z511lkceuihPPnkk3X+SKqZ0aZNG9q0aRPX9gUFBezYsYOWLVuSmZlJXl4el19+OQCTJ09OuARq\n7969Rf8tTpLc/V3g3djL+Wa2BHgGGNiw0SW23bt38/777xc/NLBx40bWrl1L69atOeKII5g1axZP\nP/00L774YsiRVqyqOtx444189tlnzJs3D4Arr7ySWbNmccMNN3DppZeydOlSFi5cSFZWVpjViNuU\nKVMYO3Ys/fv358QTT+Tee+9lz549jB07FoDRo0dz+OGHF99+mjRpEqeddhr33HMPZ511Fo8//jg5\nOTk89NBDIdYi8VR1Xsu2qzBVdQ0kinHjxvH444/zzDPPcPDBBxf39rRq1YqMjLgniq9zVX32tVbd\nx/hSeQGGYDxF8OijR9Iifv4F5/uSJUu8b9++3rZtW1+/fv0Bj0uGKTs728+/4HyPpEWKY/7hD3/o\nhx9+uKenp7uZlZriIGzF8UYiRY+YFsbO+WA/8PO4AigEepZ9L5UWyjzG/fLLL7uZeSQSKbX8/Oc/\nd3f32267zbt37158zhPp8egiVdVh7NixPnTo0FLbvPLKK96vXz/PyMjwHj16+GOPPVblcRKx7kVm\nzZrlXbt29YyMDB84cKCvWrWq+L2hQ4cWn4siCxcu9KOPPtozMjL8uOOOq3KKklSc4qCq81q2XYXZ\nPqq6BkoKM87yYiw7dU4ixOle+WdfUjzXRuiNPdEX4CogShv2MwLnxzgj8LTD0hzwpk2b+ptvvlnp\nB9jQZs+e7Wbm6e3TvWTMtAmSwIsuuiihkqhK4t1PMAbqSi/9mUyMJVEneAhtIlGW8n5R1ETYP9jC\nlMp1T9UkqiaSpX0ozroVz7Wh23mVMLMhwCwGYIwgvXgEWRQKNxXCFti3bx/79+8PM8xSli9fzvjx\n4/ETnW9GfFN61NsAYHEwg2uizIRbabzHkk42sJLZZvYvd3/NzNKBMUABoGmZRUQkNEqiKmNMpjWF\npRIogCUEI3SOhsjnESZPnsykSZOK3/7pT3/a0JEWu+fee0g7LO3AhARgNXAwWKbhBc4zzzzDxx9/\nDMDEiRNpUZ1vP27IeJ8D9gGZOAXcb2ZPAz8FjgamuPueho5XRESkiJKoCphZJnAeJxA54Jd7HmDA\nuxD1KKtWrSr1VF5YSVRBQQGLFi0iOjxa/nOXrwNfUdTdzdNPP83TTz8NwM9+9rMGT6KqjPdYYA0Q\nJQL0B7oBOcB17v5cw0Wa2LKysuKa5LVoTpd4t09mqVz3TZs2hR1Cg2ns14birFvxXBtW9AtVSjOz\n9kAuPybo96jIeuDP5c8c3NCK575IkphrGi/Qwd3zKimZUsxsYCQSWRGNRuPeRyQSoTbbJzPVPTrI\n3d8IO5b6kErXhuKsWzW9NtQTVbEdQJQvq5hLaxtE0iK0bNmyYaKqRMuWLYmkRYh+WUVDTZCYaxIv\nwQDzHfUfVVL5OhqNMn/+fHr37l3jjbOyspg2bVrc2yezVK77unXruOSSSwC+DjuWepQS14birFvx\nXBtKoirg7gUWsb+ymnMZUGZMVJEopL+VzsjzRhbPGxWmzMxMfjDiB2S9mRUMIq/DmL/++uvii2Db\ntm0cf/zx3HHHHQd8+WlN4x05ciTPvvYs3wwoZ0xULF5W8w2wyN0L4j5YI9a7d2/69etX4+2KutXj\n3T6ZpXLdU0ljvzYUZ/g0Y3llnHvZShpLCH6ZlxQFFkPhF4VMnjw5hOAOlJeXxz//+U/YCnUd85gx\nY7jvvvv42c9+xgMPPEB6ejo//OEPef3112sV85TJUyj8orDSeNlKGsGs5VKJu+++mxNPPJGWLVvS\nvn17zj//fN59992qN0wg2dnZnHvuuXTu3JlIJMIzzzxT5TYvv/wy/fv3JyMjg6OOOiohJkyMRyrX\nvb7Fc27D8uCDD9KnTx9atWpFq1atOOmkk1i8eHHYYVVo1qxZdO/enczMTAYOHMiqVavCDqmU+v65\nqCSqEu6+HBjHmziz+IYVBONzVkD6H9KxVcbs2bMZPHhwyJEGCdTJJ59MXl4eV199NbbSSP9DOnUR\n88qVK1mwYAG//vWv+fWvf83ll1/O0qVL6dq1K9dff32t4h4yZAizZ88uN15m8Q0rcWCcu6feN1vW\nUHZ2NldffTVvvvkmL774Ivv37+eMM86goCB5OvB2795N3759gzZRjWk4Nm/ezNlnn82wYcNYu3Yt\nkyZN4vLLL+eFF15ogGjrVirXvb7V9NyG6YgjjmDGjBn84x//ICcnh9NPP52RI0cm5IDsBQsWMHXq\nVG6//XbWrFlDnz59GDFiBPn5+WGHVqzefy5Wd0KpVF6AwcBCSsxYfuGFF/ry5curMX1X/cvNzfWe\nPXt6kyZNimcrXr58uV944YWlZiyPN+brrrvOmzRp4jt37iy1/u677/ZIJOKffPJJretQHG/JGcuD\nc37AjOVaittlpRMKbtmyxc3Ms7Ozy30/0SfAMzNftGhRpWWuv/56P+6440qtu/jii/3MM8+sdLtU\nrnuqT7bURSRqAAAgAElEQVRZnXObaO2jdevWPnfu3APWhx3ngAEDfOLEicWvo9God+7c2WfMmFGq\nXNhxllTZz8V4rg31RFWDu7/m7j+KRCK7b7vtNnbt3MXChQsTqgdq8+bNpb5MePDgwSxcuJBdO3eR\nm5tbq5jfeustjjrqKJo3b15q/Yknnlj8fm0Vxbts2bKiVQPc/UeuHqi4bd++HTOjdevWxet+/vOf\nM3To0BCjqltvvPHGAePyRowYwYoVK0KKqOGkct3r2m233Ub37t3DDuMA0WiUP//5z+zZsyfhvlR6\n//795OTkMGzYsOJ1Zsbw4cMTug2W93OxNjSwvAbMjBYtWiTEIHKoOIEqKTMzM6543Z2tW7eya9cu\nPvnkEzp37nxAmY4dO+LufPbZZ3HFX54SX1y5r852moLcnWuuuYYhQ4ZwzDHHFK8v+swai/Km6Wjf\nvj07duxg3759NG3atIItk18q172utWvXjh49eoQdRrF///vfDBo0iL1799KiRQuefvppevXqFXZY\npeTn51NYWFhuG9ywYUNIUVWuop+LtaEkKklVJ4GKx/bt25k3bx6zZ/+Od9/9oHj9Rx99yP3338+Y\nMWM45JBDgG8TnmQac5Mqxo0bxzvvvFM8yV2Ru+66K6SIRBLX+PHjGT9+fNhhFOvVqxdr167lq6++\nYuHChYwePZpXX3014RKpZFPRz8Xa0O28JFRfCdSSJUvo2vVwrr12Mp07b+TWW+G//xsOOwwOOmgP\n1147ma5dD2fJkiUA7N27FyBheuYkMGHCBLKysnj55Zfp2LFj2OHUqw4dOpCXV3r+1by8PFq2bNno\ne2JSue6NXXp6OkceeSTf+973uPPOO+nTpw/3339/2GGV0rZtW9LS0sptgx06dAgpqorV189FJVFJ\npj4TqLPPPotjjilgwQJn+nTntNOgf3/o0gVatYIFC5xjjing7LPPYsmSJXz++ecAdOrUqU5ikNqb\nMGECixYtYtmyZXTp0iXscOrdoEGDWLp0aal1zz//fMKNH6kPqVz3VBONRtm3L7FGODRp0oT+/fuX\naoPuztKlSznppJNCjOxA9flzUUlUEqnPW3ijRl3ICSc4d9wRpex4u+98Bz75BDIz4Y47opxwgjNq\n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\nNCaqgSmBkoYUjUbZt29f2GFUW5MmTejfvz9Lly4tXufuLF26tHhsV1mDBg0qVR7ghRdeYNCgQfUa\na9jKq/fzzz/f6OstkkjUE9WAlEBJfbrppps488wz6dKlCzt37uSPf/wjr7zyCs8//zwAN954I599\n9lnCzyU0ZcoUxo4dS//+/TnxxBO599572bNnD2PHjgVg9OjRHH744cW3JydNmsRpp53GPffcw1ln\nncXjjz9OTk4ODz30UIi1qLndu3fz/vvv4x58c8DGjRtZu3YtrVu35ogjjjjg87vyyiuZNWsWN9xw\nA5deeilLly5l4cKFZGVlhVkNkZSiJKqBKIGS+vbFF18wZswYPv/8c1q1asXxxx/P888/z+mnnw4E\nA5E//vjjkKOs2qhRo8jPz2f69Onk5eXRt29flixZQrt27QD45JNPSE//9kfXoEGD+NOf/sTNN9/M\nzTffTM+ePVm0aBHHHHNMWFWIy+rVqxk6dChmhpkxdepUIJgMd+7cuQd8ft26deO5555j8uTJPPDA\nAxx++OHMmTPngCf2RKT+KIlqAEqgpCE8/PDDlb7/yCOPNFAktTdu3DjGjRtX7nsvvfTSAesuvPBC\nLrzwwvoOq16deuqpRKPRCt8v7/M75ZRTyMnJqc+wRKQSGhNVz5RAiYiINE5KouqREigREZHGS7fz\n4vT1118zbdo05s+fz7Zt2zj++OO54447iscjJGICVVXMicbMDgauB06MLYcCY939sVADSzDxfjfe\npk2barV9MkvluqdinUXqTdjfO5NMS8nvzrv44ov9oIMO8htuuMEfeughHzx4sDdp0sRfe+21hPku\nvLIqizlRlPzuPKArEAU2AUuBQmC0J0BbSIQF6BKJRApi5yuuJRKJxL1tsi8pXvcCoEvYbViLlmRf\nzN2R6klPT9/1m9/85uAhQ4YwcOBAZs6cyeTJkwHYt28fxx57LK1bt2bbtm0J1QMFsHLlygpjbt++\nPcuXLw85wsDKlSsZMGAAwPHAeuBQd//CzPoDq1BPVClm1gVoW4tdHAR8XUfhJJtUrnu+u38UdhAi\nyU638+KwcOFC0tPTueKKK4rXNW3alIsuuog777yT9PR0/va3vyVMAgUVx3zZZZdx88038+mnn9K5\nc+cQIzyQu+8Hvgg7jkQW+0WoX4YiIiHQwPI4vPXWWxx11FE0b968eF1eXh6PPvooANOmTUuoBArK\njxngxBNPLH5fREREqk9JVBw+//xzOnbsWPy6aBB5Xl4eZlbqvURRNuYiHTt2xN357LPPQohKREQk\neSmJikNBQUHxF3yWfAqvaLLDgoKCMMMrV8mYS8rIyCh+X0RERKpPY6LikJmZyb59+w6YxqBLly7F\n7yeKgoICduzYQUZGRrlfRLt3714gsWIWERFJBuqJikPHjh35+OOPD5gH6vPPPwegU6dOIUcIy5cv\n54ILL6B5i+Z06NCBt99+mzdXvslrr71WqlwixSwiIpJMlERVk5n1jEajB/3f//0fW7duZcOGDWza\ntKnUNAZvvPEGZkbfvn1DjfX3v/89p5xyCs++9izR4VH4MdANdu7YyZAhQ3jwwQeLyyZKzADvvfce\ns2bNKno5ycx6hhmPiIhIZTRPVDWY2c8NHm4BkX5mrHJnN8EXhr788stAMBv4scceS7t27Q7o7WlI\ny5cv55RTTsFPdBjBt2nyJ8DDwBFgnxjZ2dl8//vfT4iYIfhy1Ssuv5yWZhxXWMhaKNwB5nCZuz+q\neaJERCTRKImqgpn1NFh/OUTuBzKBAuC7BNNoX3HFFXz/+9/n0UcfZfXq1bz00ksMHjw4tHgvuPAC\nnn3tWb75xTcH9jM+CawHa2p8r9f3yMjISIiY33vvPXr36sWl0Sglz/FE4OFghuV7Y6uvBP4CrIlt\n+oC77wwjZhERESVRVTCzu1vBtbmQnlFi/VfAYcB+M9ydJk2aePPmzQubNm0a2gl1d/Ly8powAhhU\nToFvgGXAamAfpKene4sWLUKNGWDnzp1p6bt3R3KBkue4ADgY8G+/rqKs7pp1WUREwqKn86rWrS9E\nMsqsbAUMBH/V/W3gL/v372fbtm0hhFfKwcBUWlfwbjrwH8ARwJ/hm2++uWfbtm27Gyy6il1wKnw3\nA6zkykzgFCh8BZ509x+HFJuIiEi5lERVbfNbEC2ASMlJAAqAt4Ivx/2bu98aUmylmFkmMJkvq3hg\nIMj1osA0dw99gigzO+gt6FUA6WXPcey+3eYQwhIREamUns6r2twdEJlI8Esdvh2vszPoOZkTWmRl\nuHsBxl9ZzTdEKygUBVbzDfB0IiRQMUlzjkVERIpoTFQ1mNlYgzktIdoXbA3BL/eiJ8fCjq8kMxsC\nvMoArNTTeRAkUIuBlThwsruH+0heCcl0jkVEREBJVLWZWQ/gMqAbwe2lOe7+fpgxVcTMrgRm04ZC\nTiCdQwlu4a3mG7aSBoxz9wcr30vDS6ZzLCIioiSqkTKzwcBk4HyC/qgo8DRwbyL1QImIiCQrJVGN\nXGyweUtgRwKNgRIREUl6SqJERERE4qCn80RERETioCRKREREJA5KokRERETioCRKREREJA5KokRE\nRETioCRKREREJA5KokRERETioCRKREREJA5KokRERETioCRKREREJA5KokRERETioCRKREREJA5K\nokRERETioCRKREREJA5KokRERETioCRKREREJA5KokRERETioCRKREREJA5KokRERETioCRKRERE\nJA5KokRERETioCRKREREJA5KokRERETioCRKREREJA5KokRERETioCRKREREJA5KokRERETioCRK\nREREJA5KokRERETioCRKREREJA5KokRERETioCRKREREJA5KokRERETioCRKREREJA5KokRERETi\noCRKREREJA5KokRERETioCRKREREJA5KokRERETioCRKREREJA5KokRERETioCRKREREJA5KokRE\nRETioCRKREREJA5KokRERETioCRKREREJA5KokRERETioCRKREREJA5KokRERETioCRKREREJA5K\nohohMzvVzKJmdkrYsYjURmNvy2a22czmlnjdqOsr9SPWZqaXeD02tq5LIsTTmCmJarw87ABE6ki9\ntmUzyzSz8Wa2xMw+M7MdZvYPM7vSzOr7Z2R5ddO1K7XllGhHFhhrZovM7CMz22Vm/zKzm82saYhx\nJj0lUSKS6o4EHoj9fyYwFdgIzAbmhBWUSB1qBswF2gK/ByYBbwK3A1khxpX00sMOQEQkZLnAse6+\nrsS6h8xsDjDWzH7l7htDik2kLnwNnOTub5RYN8fMPgRuM7PT3f2lkGJLauqJSmBm1snM5ppZrpnt\nNbN/m9nPy5TpbGZ/jXXP5pnZPUBTwMrZ33gz+8DM9pjZG2Y2xMxeNrOXypQ7yMxuN7P3Ysf9yMxm\nmNlB9VtjaawSuS27+9YyCVSRp2P/9i6zz1Zmdq+ZbYrt82Mzm2dmrWtyXJHYdTHHzD6NtZONZjbb\nzNJj77cys/ti7WdvrD1db2YHXBOVcff9ZRKoIk8TXF9l23i12m+s3L1m9kXsNvhfzaxzBXU9zcxW\nm1lBbL//ZWa3mVm0nLKXxMruMbOtZva4mR1ekzo3FPVEJSgzO4ygu7WQ4FZDPnAmwV8PLdz9ATPL\n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\nJEpEREQkDkqiREREROKgJEpEREQkDkqiREREROKgJEpEREQkDkqiREREROKgJEpEREQkDkqiRERE\nROKgJEpEREQkDkqiREREROKgJEpEREQkDkqiREREROKgJEpEREQkDkqiREREROKgJEpEREQkDkqi\nREREROKgJEpEREQkDkqiREREROKgJEpEREQkDkqiREREROKgJEpEREQkDkqiREREROKgJEpEREQk\nDkqiREREROKQHnYA1WVmXYC2tdjFQcDXdRROsknVuue7+0dhB1GfGsF1EebxU7nujf7aEGkISZFE\nmVmXSCSyIRqNZsS7j0gkQjQarcuwkkaq1j0Siew1s6Mb6y+LxnBdhHn8FK97o742RBpKUiRRQNto\nNJoxf/58evfuXeONs7KymDZtGvFun8xSte7r1q3jkksuySDopWmsvyiS+roI8/ipXPcUuTZEGkSy\nJFEA9O7dm379+tV4u3Xr1tVq+2SWynVPFcl6XYR5/FSuu4jUnaQdWD5r1iy6d+9OZmYmAwcOZNWq\nVWGH1CBStd7Z2dmce+65dO7cmUgkwjPPPBN2SAkrUdpImHGEdeyw22nYxxdJNUmZRC1YsICpU6dy\n++23s2bNGvr06cOIESPIz88PO7R6lar1Bti9ezd9+/Zl9uzZmFnY4SSsRGkjYcYR5rHDbqdhH18k\n5bh7wi9AP8BzcnLc3X3AgAE+ceJELxKNRr1z584+Y8YML8/8+fO95PbJqqb1dm88dS/JzHzRokWV\nlsnJyXHAgX6eAG24Ppay14V7zdpIfbaN6sRRX8cP89glVdZOwzx+KlwbWrQ01JJ0PVH79+8nJyeH\nYcOGFa8zM4YPH86KFSsAGDt2LEOHDg0rxHpRnXpLakuUayPMtqrrREQaUtIlUfn5+RQWFtK+fftS\n69u3b09ubi4AnTp1omvXrmGEV2+qU29JbYlybYTZVnWdiEhDSqqn86rrrrvuCjsEkYSka0NEpO4k\nXU9U27ZtSUtLIy8vr9T6vLw8OnToEFJU9S9V6y3VlyhtJMw4EuUciEhqSLokqkmTJvTv35+lS5cW\nr3N3li5dykknnRRiZPUrVest1ZcobSTMOBLlHIhIakjK23lTpkxh7Nix9O/fnxNPPJF7772XPXv2\nMHbsWABuvPFGPvvsM+bNmxduoHWsqno3Zrt37+b999/H3QHYuHEja9eupXXr1hxxxBEhR5c4EuXa\n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\ne93fzOy6djut16x1ITO+nddup9og0ptihgnGiqLEOhyOXlVVNX8EzeFw2PZcAbuu3eFwjKuqukoI\ncV92LnqwQl3IjG/ztVu6NoiCxRRNFPDqHwaARe+xif8B+DtA6ZiNXdc+YvV/EhaoC5nx7bx2y9cG\nUTCYpokiIiIiMhKeWE5ERESkAZsoIiIiIg3YRBERERFpwCaKiIiISAM2UUREREQasIkiIiIi0oBN\nFBEREZEGbKKIiIiINGATRURERKQBmygiIiIiDdhEEREREWnAJoqIiIhIAzZRRERERBqwiSIiIiLS\ngE0UERERkQZsooiIiIg0YBNFREREpAGbKCIiIiIN2EQRERERacAmioiIiEgDNlFEREREGrCJIiIi\nItKATRQRERGRBmyiiIiIiDRgE0VERESkAZsoIiIiIg3YRBERERFpwCaKiIiISAM2UUREREQasIki\nIiIi0oBNFBEREZEGbKKIiIiINGATRURERKQBmygiIiIiDdhEEREREWnAJoqIiIhIAzZRRERERBqw\niSIiIiLSgE0UERERkQZsooiIiIg0YBNFREREpAGbKCIiIiIN2EQRERERacAmioiIiEgDNlFERERE\nGrCJIiIiItKATRQRERGRBmyiiIiIiDRgE0VERESkAZsoIiIiIg3YRBERERFpwCaKiIiISAM2UURE\nREQasIkiIiIi0oBNFBEREZEG/wc4x2jkWB/p/AAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f3fe65c2ef0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from fealpy.mesh.TriangleMesh import TriangleMesh\n",
    "import matplotlib.pyplot as plt \n",
    "%matplotlib inline\n",
    "point = np.array(\n",
    "    [(0.0, 0.0),\n",
    "     (1.0, 0.0),\n",
    "     (1.0, 1.0),\n",
    "     (0.0, 1.0)], dtype=np.float)\n",
    "cell = np.array([\n",
    "        (1, 2, 0), \n",
    "        (3, 0, 2)], dtype=np.int)\n",
    "tmesh = TriangleMesh(point, cell) # 三角形网格实例\n",
    "fig, axes = plt.subplots(2, 3)\n",
    "tmesh.add_plot(axes[0, 0], cellcolor='w')\n",
    "tmesh.find_point(axes[0, 0], showindex=True, markersize=25, fontsize=12)\n",
    "tmesh.find_edge(axes[0, 0], showindex=True, markersize=50, fontsize=12)\n",
    "tmesh.find_cell(axes[0, 0], showindex=True, markersize=100, fontsize=12)\n",
    "axes[0, 0].set_title('mesh')\n",
    "\n",
    "for ax in axes.reshape(-1)[1:]:\n",
    "    ax.axis('tight')\n",
    "    ax.axis('off')\n",
    "axes[0, 1].table(cellText=point, rowLabels=['0:', '1:', '2:', '3:'], loc='center')\n",
    "axes[0, 1].set_title('point')\n",
    "axes[0, 2].table(cellText=cell, rowLabels=['0:', '1:'], loc='center')\n",
    "axes[0, 2].set_title('cell')\n",
    "axes[1, 0].table(cellText=tmesh.ds.edge, rowLabels=['0:', '1:', '2:', '3:', '4:'],  loc='center')\n",
    "axes[1, 0].set_title('edge')\n",
    "axes[1, 1].table(cellText=tmesh.ds.edge2cell, rowLabels=['0:', '1:', '2:', '3:', '4:'],  loc='center')\n",
    "axes[1, 1].set_title('edge2cell')\n",
    "axes[1, 2].table(cellText=tmesh.ds.cell_to_edge(), rowLabels=['0:', '1:'],  loc='center')\n",
    "axes[1, 2].set_title('cell2edge')\n",
    "plt.tight_layout(pad=1, w_pad=1, h_pad=1.0)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3、任意 $p$ Lagrange 有限元空间"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.1 三角形单元上的重心坐标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\nCqhoXgAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f3fe68cca58>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from fealpy.mesh.TriangleMesh import TriangleMesh\n",
    "\n",
    "from matplotlib.font_manager import FontProperties\n",
    "cfont = FontProperties('SimHei')\n",
    "\n",
    "point = np.array([\n",
    "    [0,0],\n",
    "    [1,0],\n",
    "    [0,1]], dtype=np.float)\n",
    "cell = np.array([[0, 1, 2]], dtype=np.int)\n",
    "\n",
    "mesh = TriangleMesh(point, cell)\n",
    "fig = plt.figure()\n",
    "axes = fig.gca()\n",
    "mesh.add_plot(axes, cellcolor='w')\n",
    "mesh.find_point(axes, showindex=True, fontsize=12, color='g', markersize=25)\n",
    "axes.set_title(u'三角形单元 $\\\\tau$', fontproperties=cfont)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "给定三角形单元 $\\tau$, 其三个顶点 $\\mathbf x_0 :=(x_0,y_0)$, $\\mathbf x_1 :=(x_1,y_1)$ 和 $\\mathbf x_2 :=(x_2,y_2)$ 逆时针排列, 且不在同一条直线上, 那么向量 $\\vec{\\mathbf x_0\\mathbf x_1}$ 和 $\\vec{\\mathbf x_0\\mathbf x_2}$ 是线性无关的. 这等价于矩阵\n",
    "\n",
    "$$\n",
    "A = \n",
    "\\begin{pmatrix}\n",
    "x_0 & x_1 & x_2 \\\\\n",
    "y_0 & y_1 & y_2 \\\\\n",
    "1   & 1   & 1 \n",
    "\\end{pmatrix}\n",
    "$$\n",
    "\n",
    "非奇异. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任给一点 $\\mathbf{x}:=(x,y)\\in\\tau$, 求解下面的线性方程组\n",
    "\n",
    "$$\n",
    "A \n",
    "\\begin{pmatrix}\n",
    "\\lambda_0 \\\\\n",
    "\\lambda_1\\\\\n",
    "\\lambda_2  \n",
    "\\end{pmatrix}\n",
    "=\\begin{pmatrix}\n",
    "x \\\\\n",
    "y\\\\\n",
    "1  \n",
    "\\end{pmatrix}\n",
    "$$\n",
    "\n",
    "可得唯一的一组解$\\lambda_0,\\lambda_1,\\lambda_2$. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "因此对任意二维点 $\\mathbf{x}\\in\\tau$, 有\n",
    "\n",
    "$$\n",
    "\\mathbf{x}=\\lambda_0(\\mathbf{x})\\mathbf{x}_0 + \\lambda_1(\\mathbf{x})\\mathbf{x}_1 + \\lambda_2(\\mathbf{x})\\mathbf{x}_2 \n",
    "\\text{ 且 } \\lambda_0(\\mathbf{x}) + \\lambda_1(\\mathbf{x}) + \\lambda_2(\\mathbf{x}) = 1. \n",
    "$$\n",
    "\n",
    "$\\lambda_0,\\lambda_1,\\lambda_2$ 称为点 $\\mathbf{x}$ 关于点 $\\mathbf{x}_0,\\mathbf{x}_1$ 和$\\mathbf{x}_2$ 的**重心坐标**. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "易知, $\\lambda_0, \\lambda_1, \\lambda_2$ 都是关于 $\\mathbf x$ 的线性函数, 且有\n",
    "\n",
    "\\begin{eqnarray*}\n",
    "\\lambda_0(\\mathbf x_0) = 1,\\quad & \\lambda_0(\\mathbf x_1) = 0,\\quad& \\lambda_0(\\mathbf x_2) = 0\\\\\n",
    "\\lambda_1(\\mathbf x_0) = 0,\\quad & \\lambda_1(\\mathbf x_1) = 1,\\quad& \\lambda_1(\\mathbf x_2) = 0\\\\\n",
    "\\lambda_2(\\mathbf x_0) = 0,\\quad & \\lambda_2(\\mathbf x_1) = 0,\\quad & \\lambda_2(\\mathbf x_2) = 1\\\\\n",
    "\\end{eqnarray*}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$\\lambda_0, \\lambda_1, \\lambda_2$ 关于 $\\mathbf x$ 的梯度分别为:\n",
    "\n",
    "$$\n",
    "\\begin{aligned}\n",
    "\\nabla\\lambda_0 = \\frac{1}{2|\\tau|}(\\mathbf x_2 - \\mathbf x_1)W\\\\\n",
    "\\nabla\\lambda_1 = \\frac{1}{2|\\tau|}(\\mathbf x_0 - \\mathbf x_2)W\\\\\n",
    "\\nabla\\lambda_2 = \\frac{1}{2|\\tau|}(\\mathbf x_1 - \\mathbf x_0)W\\\\\n",
    "\\end{aligned}\n",
    "$$\n",
    "\n",
    "其中 \n",
    "\n",
    "$$\n",
    "W = \\begin{pmatrix}\n",
    "0 & 1\\\\ -1 & 0 \n",
    "\\end{pmatrix}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**目标:** \n",
    "\n",
    "给定有 $NC$ 个三角形单元的网格, 计算所有单元上的 $\\nabla \\lambda_0$, $\\nabla \\lambda_1$ 和 $\\nabla \\lambda_2$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里需要一个三维数组来存储所有单元上的梯度. \n",
    "\n",
    "记三维数组为 $Dlambda$, 则 $Dlambda[i, j, k]$ 存储第 $i$ 个单元上的第 $j$ 个重心坐标的梯度的第 $k$ 个分量的值, 其中 $0 \\leq i \\leq NC-1$, $ 0 \\leq j \\leq 2$, $ 0 \\leq k \\leq 1$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dlambda:\n",
      " [[[ 1. -1.]\n",
      "  [ 0.  1.]\n",
      "  [-1.  0.]]\n",
      "\n",
      " [[-1.  1.]\n",
      "  [ 0. -1.]\n",
      "  [ 1.  0.]]]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "point = np.array(\n",
    "    [(0.0, 0.0),\n",
    "     (1.0, 0.0),\n",
    "     (1.0, 1.0), \n",
    "     (0.0, 1.0)], dtype=np.float)\n",
    "cell = np.array([\n",
    "        (1, 2, 0), \n",
    "        (3, 0, 2)], dtype=np.int)\n",
    "NC = cell.shape[0]\n",
    "v0 = point[cell[:, 2], :] - point[cell[:, 1], :] # x_2 - x_1\n",
    "v1 = point[cell[:, 0], :] - point[cell[:, 2], :] # x_0 - x_2\n",
    "v2 = point[cell[:, 1], :] - point[cell[:, 0], :] # x_1 - x_0\n",
    "nv = np.cross(v2, -v1)\n",
    "\n",
    "Dlambda = np.zeros((NC, 3, 2), dtype=np.float)\n",
    "length = nv\n",
    "W = np.array([[0, 1], [-1, 0]], dtype=np.int)\n",
    "Dlambda[:,0,:] = v0@W/length.reshape(-1, 1)\n",
    "Dlambda[:,1,:] = v1@W/length.reshape(-1, 1)\n",
    "Dlambda[:,2,:] = v2@W/length.reshape(-1, 1)\n",
    "print('Dlambda:\\n', Dlambda)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2  三角形单元上的 $p$ 次基函数公式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "给定三角形单元上的一个重心坐标 $(\\lambda_0, \\lambda_1, \\lambda_2)$, 所有 $p\\geq 1$ 次基函数的计算公式如下:\n",
    "\n",
    "$$\n",
    "\\phi_{m,n,k} = \\frac{p^p}{m!n!k!}\\prod_{l_0 = 0}^{m - 1}\n",
    "(\\lambda_0 - \\frac{l_0}{p}) \\prod_{l_1 = 0}^{n-1}(\\lambda_1 -\n",
    "\\frac{l_1}{p}) \\prod_{l_2=0}^{k-1}(\\lambda_2 - \\frac{l_2}{p}).\n",
    "$$\n",
    "\n",
    "其中 $ m\\geq 0$, $n\\geq 0$, $ k \\geq 0$, 且 $m+n+k=p$, 这里规定:\n",
    "\n",
    "$$\n",
    " \\prod_{l_i=0}^{-1}(\\lambda_i - \\frac{l_i}{p}) := 1,\\quad i=0, 1, 2\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**注:**\n",
    "\n",
    "三维情形的基函数表示如下:\n",
    "$$\n",
    "\\phi_{m,n,k,v} = \\frac{p^p}{m!n!k!v!}\\prod_{l_0 = 0}^{m - 1}\n",
    "(\\lambda_0 - \\frac{l_0}{p}) \\prod_{l_1 = 0}^{n-1}(\\lambda_1 -\n",
    "\\frac{l_1}{p}) \\prod_{l_2=0}^{k-1}(\\lambda_2 - \\frac{l_2}{p})\\prod_{l_3=0}^{v-1}(\\lambda_3 - \\frac{l_3}{p}).\n",
    "$$\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.3 基函数的矩阵计算公式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**目标:**\n",
    "\n",
    "给定重心坐标 $(\\lambda_0, \\lambda_1, \\lambda_2)$, 利用**面向数组**的方式计算 $p$ 次元所有基函数在 $(\\lambda_0, \\lambda_1, \\lambda_2)$ 处的**函数值**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构造向量：\n",
    "$$\n",
    "P = ( \\frac{1}{0!},  \\frac{1}{1!}, \\frac{1}{2!}, \\cdots, \\frac{1}{p!})\n",
    "$$\n",
    "\n",
    "构造矩阵：\n",
    "$$\n",
    "A :=                                                                            \n",
    "\\begin{pmatrix}  \n",
    "1  &  1  & 1 \\\\\n",
    "\\lambda_0 & \\lambda_1 & \\lambda_2\\\\                                             \n",
    "\\lambda_0 - \\frac{1}{p} & \\lambda_1 - \\frac{1}{p} & \\lambda_2 - \\frac{1}{p}\\\\   \n",
    "\\vdots & \\vdots & \\vdots \\\\                                                     \n",
    "\\lambda_0 - \\frac{p - 1}{p} & \\lambda_1 - \\frac{p - 1}{p} & \\lambda_2 - \\frac{p - 1}{p}\n",
    "\\end{pmatrix}                                                                   \n",
    "$$ "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对 $A$ 的每一列做累乘运算, 并左乘由 $P$ 形成的对角矩阵, 得矩阵:\n",
    "\n",
    "$$\n",
    "B = \\mathrm{diag}(P)\n",
    "\\begin{pmatrix}\n",
    "1 & 1 & 1 \\\\\n",
    "\\lambda_0 & \\lambda_1 & \\lambda_2\\\\\n",
    "\\prod_{l=0}^{1}(\\lambda_0 - \\frac{l}{p}) & \\prod_{l=0}^{1}(\\lambda_1 - \\frac{l}{p})\n",
    "& \\prod_{l=0}^{1}(\\lambda_2 - \\frac{l}{p}) \\\\\n",
    "\\vdots & \\vdots & \\vdots \\\\\n",
    "\\prod_{l=0}^{p-1}(\\lambda_0 - \\frac{l}{p}) & \\prod_{l=0}^{p-1}(\\lambda_1 - \\frac{l}{p})\n",
    "& \\prod_{l=0}^{p-1}(\\lambda_2 - \\frac{l}{p}) \n",
    "\\end{pmatrix}\n",
    "$$\n",
    "\n",
    "易知, 只需从 $B$ 的每一列中各选择一项相乘(要求三项次数之和为 $p$), 再乘以 $p^p$ 即可得到相应的基函数, 其中取法共有 \n",
    "\n",
    "$$\n",
    "n_{dof} = {(p+1)(p+2)\\over 2}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "即需要构造 $n_{dof}\\times 3$ 的指标矩阵 $I$, 则基函数可写成如下形式 \n",
    "\n",
    "$$\n",
    "\\phi_i = p^pB_{I_{i,0}, 0}B_{I_{i, 1},1}B_{I_{i, 2}, 2}, \\quad i = 0, 1, \\cdots, n_{dof}\n",
    "$$\n",
    "\n",
    "对应 `Python` 的代码如下:\n",
    "\n",
    "```Python\n",
    "phi = p**p*np.prod(B[I, [0, 1, 2]], axis=1)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\nZswYVq5axYNz5vCaMaRZyx5jut1uT7Z9uXY9xligVI+0iU5VVVWOPbeyJ2zZsgVQTqccOXKkx/dh\nmkf293bGmJuBfZs3b+aOO+5wO05E2bdvH3fccceFkydPHrxw4YIKq17EGJMMLAG+97Of/Yx58+Z1\nq/BpdujQIVatWtUyl9ScOXMcabcn226v3WPHjnH33XeHgsHgxmAwqMIqShhjsj0ez9ZIG4/THo/H\nE3HjhtoTZTnHW2u39UT7KqouUlF1eSqsei9jzL3Aa4FAgISEBLfjRJzq6moVVlHGGJMB+CoqKkhN\nTXU7ToeqqqooKSlBOZ1RV1dHfn4+QKa1dldP7EOX/6RTdClQpH3tzLyuwipKpKamkpGR4XaMDjVf\nSlPO6KGB6tJpGrwu0j49K1BEQEWVXCUVViLtU2ElnVFTU8P06dMZOnQoHo+HyspKtyNd1vLlyxk5\nciT9+vUjOzubHTt2uB2plbKyMtLS0oiPjyc+Pp6cnBzefvtt1/KoqJKrpsJKpH0qrORK6uvrSU9P\nZ8WKFV2aNy2c1q1bR3FxMYsXL2b37t2kpaUxZcoUAoGA29FaDBs2jCVLlrBr1y58Ph+TJk1ixowZ\nrt2FqKKqHefPn+eXv/wlQ4cOpX///mRnZ7Nx40a3Y0UUJworY8wAY8xiY8xbxpjPjDEhY0z4nysg\nndZT50Z9fT1PPPEEU6dOJSEhAY/Hw29/+9tut7t3715mzpzJ6NGjGTBgAIMHD2bixIm8+eab3W4b\nYNeuXUyfPp2EhAQGDBjAN7/5Terq6rpdWF3NuWGMSTHGvG2MOXVx298aYxK7/9NJT8jLy+PJJ59k\nxowZRPqNYqWlpcydO5eCggJSUlIoKyujf//+EfWYmmnTppGXl8fo0aNJTk7m6aefJi4ujm3beuTm\nvitSUdWOWbNm8fzzz/PjH/+YZcuWERMTw913381//dd/uR0tojhQWCUCJUAKsIfWj/GQCNRT50Yg\nEOCpp55i3759pKenO/YJ/tixY5w+fZrCwkKWLVvGokWLMMYwffp0Vq5c2a22N2zYQE5ODoFAgEWL\nFrFs2TLuuecePvzwQyd6rDp1bhhjhgI1wCjgfwL/BkwDNhhjdCOSdFljYyM+n6/Vo52MMeTm5rJ1\n61YXk3UsFAqxdu1aGhoaGD9+vDshrLVamj4t3AzYsrIya4yxv/71r22zs2fP2uTkZHv77bdbaauu\n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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7ff654651fd0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import sys\n",
    "\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from fealpy.functionspace.tools import function_space\n",
    "from fealpy.mesh.TriangleMesh import TriangleMesh\n",
    "\n",
    "from matplotlib.font_manager import FontProperties\n",
    "cfont = FontProperties('SimHei')\n",
    "\n",
    "degree = 4\n",
    "\n",
    "point = np.array([\n",
    "    [0,0],\n",
    "    [1,0],\n",
    "    [0,1]], dtype=np.float)\n",
    "cell = np.array([[0, 1, 2]], dtype=np.int)\n",
    "\n",
    "mesh = TriangleMesh(point, cell)\n",
    "V = function_space(mesh, 'Lagrange', degree)\n",
    "\n",
    "ipoints = V.interpolation_points()\n",
    "cell2dof = V.cell_to_dof()\n",
    "fig, axes = plt.subplots(1, 3)\n",
    "mesh.add_plot(axes[0], cellcolor='w')\n",
    "mesh.find_point(axes[0], showindex=True, fontsize=12, color='g', markersize=25)\n",
    "axes[0].set_title(u'三角形顶点局部编号', fontproperties=cfont)\n",
    "\n",
    "mesh.add_plot(axes[1], cellcolor='w')\n",
    "mesh.find_point(axes[1], point=ipoints[cell2dof[0]], showindex=True, fontsize=12, markersize=25)\n",
    "axes[1].set_title(str(degree) + u' 次元局部自由度编号', fontproperties=cfont)\n",
    "\n",
    "axes[2].axis('tight')\n",
    "axes[2].axis('off')\n",
    "axes[2].table(cellText=V.cellIdx, loc='center')\n",
    "axes[2].set_title(str(degree) + u' 次元基函数指标矩阵 $I$', fontproperties=cfont)\n",
    "plt.tight_layout(pad=1, w_pad=1, h_pad=1.0)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.4 基函数梯度的计算公式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**目标:**\n",
    "\n",
    "给定重心坐标 $(\\lambda_0, \\lambda_1, \\lambda_2)$, 利用**面向数组**的方式计算 $p$ 次元所有基函数在 $(\\lambda_0, \\lambda_1, \\lambda_2)$ 处的梯度值."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**分析:**\n",
    "\n",
    "根据求导法则, 关键是计算出矩阵\n",
    "\n",
    "$$\n",
    "B = \\mathrm{diag}(P)\n",
    "\\begin{pmatrix}\n",
    "1 & 1 & 1 \\\\\n",
    "\\lambda_0 & \\lambda_1 & \\lambda_2\\\\\n",
    "\\prod_{l=0}^{1}(\\lambda_0 - \\frac{l}{p}) & \\prod_{l=0}^{1}(\\lambda_1 - \\frac{l}{p})\n",
    "& \\prod_{l=0}^{1}(\\lambda_2 - \\frac{l}{p}) \\\\\n",
    "\\vdots & \\vdots & \\vdots \\\\\n",
    "\\prod_{l=0}^{p-1}(\\lambda_0 - \\frac{l}{p}) & \\prod_{l=0}^{p-1}(\\lambda_1 - \\frac{l}{p})\n",
    "& \\prod_{l=0}^{p-1}(\\lambda_2 - \\frac{l}{p}) \n",
    "\\end{pmatrix}\n",
    "$$\n",
    "\n",
    "中每个元素的梯度. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构造矩阵:\n",
    "$$\n",
    "F^i = \n",
    "\\begin{pmatrix}\n",
    "1 & \\lambda_i & \\cdots & \\lambda_i \\\\\n",
    "\\lambda_i - \\frac{1}{p} & 1 & \\cdots & \\lambda_i - \\frac{1}{p} \\\\\n",
    "\\vdots & \\vdots & \\ddots & \\vdots \\\\\n",
    "\\lambda_i - \\frac{p-1}{p} & \\lambda_i - \\frac{p-1}{p} & \\cdots & 1\n",
    "\\end{pmatrix}_{p\\times p}\n",
    ", \\quad i = 0, 1, 2\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "记\n",
    "$$\n",
    "f_{i,j} = \\sum_{m=0}^j\\prod_{k=0}^j F^i_{k, m},\\quad i = 0, 1, 2, 0 \\leq j \\leq p-1.\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$$\n",
    "\\begin{aligned}\n",
    "\\nabla B = &  \n",
    "\\mathrm{diag}(P)\n",
    "\\begin{pmatrix}\n",
    "0 & 0 & 0\\\\\n",
    "\\nabla \\lambda_1 & \\nabla \\lambda_2 & \\nabla \\lambda_3\\\\\n",
    "\\nabla \\prod_{l=0}^{1}(\\lambda_1 - \\frac{l}{p}) & \n",
    "\\nabla \\prod_{l=0}^{1}(\\lambda_2 - \\frac{l}{p}) &\n",
    "\\nabla \\prod_{l=0}^{1}(\\lambda_3 - \\frac{l}{p}) \\\\\n",
    "\\vdots & \\vdots & \\vdots \\\\\n",
    "\\nabla \\prod_{l=0}^{p-1}(\\lambda_1 - \\frac{l}{p}) &\n",
    "\\nabla \\prod_{l=0}^{p-1}(\\lambda_2 - \\frac{l}{p}) &\n",
    "\\nabla \\prod_{l=0}^{p-1}(\\lambda_3 - \\frac{l}{p}) \n",
    "\\end{pmatrix}\\\\\n",
    "= & \\mathrm{diag}(P)\n",
    "\\begin{pmatrix}\n",
    "0 & 0 & 0 \\\\\n",
    "\\nabla \\lambda_1 & \\nabla \\lambda_2 & \\nabla \\lambda_3\\\\\n",
    "f_{0,0} \\nabla \\lambda_1 & \n",
    "f_{1,0} \\nabla \\lambda_2 &\n",
    "f_{2,0} \\nabla \\lambda_3 \\\\\n",
    "\\vdots & \\vdots & \\vdots \\\\\n",
    "f_{0, p-1} \\nabla \\lambda_1 &\n",
    "f_{1, p-1} \\nabla \\lambda_2 &\n",
    "f_{2, p-1} \\nabla \\lambda_3 \n",
    "\\end{pmatrix}\\\\\n",
    "= & \\mathrm{diag}(P)\n",
    "\\begin{pmatrix}\n",
    "0 & 0 & 0\\\\\n",
    "1 & 1 & 1\\\\\n",
    "f_{0,0} & \n",
    "f_{1,0} &\n",
    "f_{2,0} \\\\\n",
    "\\vdots & \\vdots & \\vdots \\\\\n",
    "f_{0, p-1} &\n",
    "f_{1, p-1} &\n",
    "f_{2, p-1}  \n",
    "\\end{pmatrix}\n",
    "\\begin{pmatrix}\n",
    "\\nabla \\lambda_1 & 0 & 0\\\\\n",
    "0 & \\nabla \\lambda_2 & 0 \\\\\n",
    "0 & 0 & \\nabla \\lambda_3\n",
    "\\end{pmatrix}\n",
    "\\end{aligned}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "记 \n",
    "$$\n",
    "F =\n",
    "\\mathrm{diag}(P)\n",
    "\\begin{pmatrix}\n",
    "0 & 0 & 0\\\\\n",
    "1 & 1 & 1\\\\\n",
    "f_{0,0} & \n",
    "f_{1,0} &\n",
    "f_{2,0} \\\\\n",
    "\\vdots & \\vdots & \\vdots \\\\\n",
    "f_{0, p-1} &\n",
    "f_{1, p-1} &\n",
    "f_{2, p-1}  \n",
    "\\end{pmatrix}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "利用前面的矩阵 $B$, $I$, $Dlambda$, 如下代码即可计算所有单元上的 $p$ 次元基函数的导数:\n",
    "\n",
    "```Python\n",
    "pp = p**p\n",
    "ldof = (p+1)*(p+2)/2\n",
    "Q = B[I,[0,1,2]]\n",
    "M = F[I,[0,1,2]]\n",
    "R = np.zeros((ldof,3), dtype=np.float)\n",
    "R[:,0] = M[:,0]*Q[:,1]*Q[:,2]\n",
    "R[:,1] = Q[:,0]*M[:,1]*Q[:,2]\n",
    "R[:,2] = Q[:,0]*Q[:,1]*M[:,2]\n",
    "gradphi = np.einsum('ij, kj...->ki...', pp*R, Dlambda) # 爱因斯坦求和 \n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "<h1><center>谢谢大家！</center></h1>\n",
    "<h1><center>欢迎批评指正！</center></h1>"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Slideshow",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
